TypeScript 50.6%
JavaScript 46.1%
SQL 2.1%
Shell 0.6%
CSS 0.5%
1import { NextRequest, NextResponse } from "next/server";2import { z } from "zod";3import { and, eq } from "drizzle-orm";4import { db } from "@/db/client";5import { listingMedia } from "@/db/schema";6import { assertSameOrigin, requireUser } from "@/lib/auth/session";7import { getListingFull, assertOwner } from "@/lib/listings/service";8import { apiError, handle, parseBody } from "@/lib/api";9export const dynamic = "force-dynamic";10const Body = z.object({ order: z.array(z.string().uuid()).max(40).optional(), captions: z.record(z.string().uuid(), z.string().max(140)).optional() });11/** Confirme l'état des médias d'une annonce : ordre et légendes (les fichiers sont déjà traités à l'upload). */12export async function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {13 try {14 await assertSameOrigin(); const u = await requireUser(); const { id } = await params; const b = await parseBody(req, Body);15 const l = await getListingFull(id); if (!l) return apiError(404, "not_found", "Annonce introuvable"); assertOwner(l, u.id, u.roles);16 const d = db();17 if (b.order) for (const [i, mid] of b.order.entries()) await d.update(listingMedia).set({ position: i }).where(and(eq(listingMedia.id, mid), eq(listingMedia.listingId, id)));18 if (b.captions) for (const [mid, alt] of Object.entries(b.captions)) await d.update(listingMedia).set({ altText: alt }).where(and(eq(listingMedia.id, mid), eq(listingMedia.listingId, id)));19 return NextResponse.json({ ok: true, media: (await getListingFull(id))!.media.map((m) => ({ id: m.id, position: m.position, altText: m.altText })) });20 } catch (e) { return handle(e); }21}22